
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <assert.h>
#include "addrlist.c"





/* --- Helper Functions --------------------------------------------------- */
#ifndef __VERIFY
#define INPUT_BUF_SIZE 1024
#else
#define INPUT_BUF_SIZE 10
#endif
char *input (int n)
 {
	static char buf[INPUT_BUF_SIZE];
	char c;
	int  i;

	i = 0;
	while (c != '\n' && i <= n && i < INPUT_BUF_SIZE-1)
	{ 
		c = getchar();
		printf ("%c", c);
		if (c != '\n' ) { buf[i] = c; i++; } 
	}

	buf[i] = '\0';

	return (buf);
 }

/* --- Address Book Functionality ----------------------------------------- */
#ifndef __VERIFY
#define check_abort          { printf ("abort (y/n)? "); \
                               c = 0; while (c != 'y' && c != 'n') \
                                { c = getchar(); printf ("%c", c); } \
                               if (c == 'y') { goto ABORT_INPUT; } }
#else
#define check_abort ;
#endif
#define get_string(tag, dst) {  printf (tag); \
                               tmp = input (INPUT_BUF_SIZE); \
				if (strlen(tmp) == 0) { check_abort } \
				dst=(char*) my_malloc(INPUT_BUF_SIZE*(sizeof(char))); \
				dst=strcpy(dst,tmp);}


struct address *input_addr ()
 {
	struct address *address;
	char *tmp, *name = NULL, *addr = NULL, *phone = NULL;
	char c;
	get_string ("name: ", name);
	get_string ("address: ", addr);
	get_string ("phone: ", phone);
	address = (struct address*) my_malloc (sizeof(struct address));
	address->name    = name;
	address->address = addr;
	address->phone   = phone;
	return (address);

	ABORT_INPUT:
	if (name)  { free (name); }
	if (addr)  { free (addr); }
	if (phone) { free (phone); }
	return (NULL);
 }
void print_addr (struct address *addr)
 {
	assert(addr!=NULL);
	assert(addr->name!=NULL);
	assert(addr->address!=NULL);
	assert(addr->phone!=NULL);
	printf("%s; ",addr->name);
	printf ("%s; %s\n", addr->address, addr->phone);
	return;
 }

void test_print_addr()
{	
	struct address *addr;
	addr = my_malloc (sizeof(struct address));
	addr->name    = "NAME";
	addr->address = "Addres";
	addr->phone   = "PHONE";
	struct list_element *elem = NULL;
	elem = list_new_elem(addr);
	print_addr(elem->addr);
}

void list_addrs (struct list *list)
 {
	assert(list != NULL);
	struct list_element *elem =  list->first;
	unsigned int i;
	i = 0;
	while (elem)
	{
		printf ("%04u:\n  ", i);
		assert(elem->addr != NULL);
		print_addr (elem->addr);

		if (elem == list->last)
		{ elem = NULL; }
		else
		{ elem = elem->next; }
		i++; 
	}
	return;
}

void test_list_addrs()
{
	struct list *newlist = NULL;
	newlist=list_new ();
	int i, bound;
	bound=5;
	for(i=0;i<bound;++i){
		struct address *addr;
		addr = my_malloc (sizeof(struct address));
		addr->name    = "NAME";
		addr->address = "Addres";
  		addr->phone   = "PHONE";
		list_append(newlist,addr);
	}
	list_addrs(newlist);
}

void del_addr (struct list *list)
 {
	assert(list != NULL);
	struct list_element *elem = NULL;
	unsigned int i, n;
	char *tmp;

	printf ("delete #: ");
	tmp = input (INPUT_BUF_SIZE);
	n = atoi (tmp);

	elem = list->first;
	i = 0;
	while (elem && i != n)
		{
		if (elem == list->last)
		{ elem = NULL; }
		else
		{ elem = elem->next; }
		i++; }
	list_remove (list, elem);

	return;
 }
void test_delete_addrs()
{
	struct list *newlist = NULL;
	newlist=list_new ();
	int i, bound;
	bound=5;
	for(i=0;i<bound;++i){
		struct address *addr;
		addr = my_malloc (sizeof(struct address));
		addr->name    = "NAME";
		addr->address = "Addres";
  		addr->phone   = "PHONE";
		list_append(newlist,addr);
	}
	del_addr(newlist);
}

int cmp_addr (struct address *addr, char *str)
 {
	assert(str != NULL);
	assert(addr != NULL);
	assert(addr->name != NULL);
	if (strcasestr (addr->name, str))    { return (1); }
	assert(addr->address != NULL);
	if (strcasestr (addr->address, str)) { return (1); }
	assert(addr->phone != NULL);
	if (strcasestr (addr->phone, str))   { return (1); }

	return (0);
 }
void test_cmp_addr()
{
	struct address *addr;
	addr = my_malloc (sizeof(struct address));
	addr->name    = "NAME";
	addr->address = "Addres";
	addr->phone   = "PHONE";
	struct list_element *elem = NULL;
	elem = list_new_elem(addr);
	print_addr(elem->addr);	
	char *tofind;
	tofind = "a";
	cmp_addr(elem->addr, tofind);	
}

void search_addr (struct list *list)
 {
	assert(list != NULL);
	struct list_element *elem = NULL;
	unsigned int i;
	char *str;

	printf ("search: ");
	str = input (INPUT_BUF_SIZE);

	elem = list->first;
	i = 0;
	while (elem)
	{
		assert(elem->addr!=NULL);
		if (cmp_addr (elem->addr, str))
		{ 
			printf ("%04u:\n  ", i);
			print_addr (elem->addr); 
		}

		if (elem == list->last)
		{ elem = NULL; }
		else
		{ elem = elem->next; }
		i++; 
	}

	return;
 }

void test_search_addr()
{
	struct list *newlist = NULL;
	newlist=list_new ();
	int i, bound;
	bound=5;
	for(i=0;i<bound;++i){
		struct address *addr;
		addr = my_malloc (sizeof(struct address));
		addr->name    = "NAME";
		addr->address = "Addres";
  		addr->phone   = "PHONE";
		list_append(newlist,addr);
	}
	search_addr(newlist);
}
/* --- main() ------------------------------------------------------------- */

int main (int argc, char **argv)
 {
	struct termios oldT, newT;
	struct list *list = NULL;
	char c = 0;


	/* terminal setup */
	ioctl(0,TCGETS,&oldT);
	newT=oldT;
	newT.c_lflag &= ~ECHO;
	newT.c_lflag &= ~ICANON;
	ioctl(0,TCSETS,&newT);


	/* list initialisation */
	list = list_new ();

	/* main loop */
	while (c != 'q')
	{
	printf ("a: add; l: list; d: delete; s: search; q: quit\n");
	c = getchar();
	if (c != '\n') { printf ("%c\n", c); }
	switch (c) {
	case 'a': { struct address *addr;
		 addr = input_addr();
		 list_append (list, addr);
		 break; }
	case 'l': { list_addrs (list);
		 break; }
	case 'd': { del_addr (list);
		 break; }
	case 's': { search_addr (list);
		 break; }
	default : { break; } }
	}

	/* cleanup */
	list_release (list);


	/* restore terminal settings */
	ioctl(0,TCSETS,&oldT);

	return (0);
 }

